	//
	//  JsNetworkReachablitiyMonitorA.m
	//  JsUtilitySdk
	//
	//  Created by Gikki Ares on 2023/5/23.
	//

#import "JsNetworkReachablitiyManagerA.h"
#import "JsAfNetworkReachabilityManager.h"
#import <NetworkExtension/NetworkExtension.h>
#import "JsLogManager.h"
#import <CoreTelephony/CTCellularData.h>

NSString * const JsNetworkReachabilityChangeNotification = @"JsNetworkReachabilityChangeNotification";
NSString * const JsNetworkingReachabilityStatusKey = @"JsNetworkingReachabilityStatusKey";
static NSString * TAG = @"JsNetworkReachablitiyManagerA";
/**
 依赖AfNetworkReachabilityManager的实现.
 但是好像不满足条件,因为如果是wifi和流量同时开启,只能返回一个.
 */

typedef enum _JsNetworkReachablitiyManagerAStatus {
	StatusStopped,
	StatusStopping,
	StatusStarting,
	StatusStarted
}JsNetworkReachablitiyManagerAStatus;


@interface JsNetworkReachablitiyManagerA() {
	JsAfNetworkReachabilityManager * mExecutor;
	nw_path_monitor_t mPathMonitor_cellular;
	nw_path_status_t mNwStatus_cellular;
	JsNetworkReachablitiyManagerAStatus mStatus;
	JsAfNetworkReachabilityStatus mAfStatus;
}

@end

@implementation JsNetworkReachablitiyManagerA

+ (instancetype)sharedInstance {
	static JsNetworkReachablitiyManagerA * _sharedInstance;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		_sharedInstance = [[JsNetworkReachablitiyManagerA alloc]init];
	});
	return _sharedInstance;
}

- (instancetype)init {
	if(self = [super init]) {
			//默认创建一个空的sockeaddr.
			//内部实现主要是创建了一个SCNetworkReachabilityRef.
			//注册通知.
		mExecutor = [JsAfNetworkReachabilityManager manager];
	}
	return self;
}

-(BOOL)isWifiReachable {
	return [mExecutor isReachableViaWiFi];
}

-(BOOL)isCellularReachable {
	return [mExecutor isReachableViaWWAN];
}

-(void)startMonitoring {
		//注册通知
	mStatus = StatusStarting;
	self.reachabilityStatus = JsNetworkReachablitiyStatusUnknown;
	mPathMonitor_cellular = nw_path_monitor_create_with_type(nw_interface_type_cellular);
	nw_path_monitor_set_update_handler(mPathMonitor_cellular, ^(nw_path_t  _Nonnull path) {
		nw_path_status_t status = nw_path_get_status(path);
		self->mNwStatus_cellular = status;
		if(self->mStatus == StatusStarting) {
			//开始中,收到afstatus后再更新状态.
			self->mStatus = StatusStarted;
			[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onNetworkReachabilityChange:) name:JsAfNetworkingReachabilityDidChangeNotification object:nil];
			[self->mExecutor startMonitoring];
		}
		else {
			//已开启,直接更新状态.
			[self updateStatus];
		}
//		jslogd_c(TAG, @"dbugger", @"current cellular status is:%d,%@",status,[self stringForNwPathStatus:status]);
	});
	nw_path_monitor_set_queue(mPathMonitor_cellular, dispatch_get_global_queue(0, 0));
	nw_path_monitor_start(mPathMonitor_cellular);
}
- (NSString *)statusString {
	switch(self.reachabilityStatus) {
		case JsNetworkReachablitiyStatusNotReachable:
			return @"NotReachable";
		case JsNetworkReachablitiyStatusReachableViaWiFi:
			return @"WiFi";
		case JsNetworkReachablitiyStatusReachableViaWCellular:
			return @"Cellular";
		case JsNetworkReachablitiyStatusReachableViaWiFiAndCellular:
			return @"WifiAndCellular";
		default:
		case JsNetworkReachablitiyStatusUnknown:{
			return @"Unkown";
		}
	}
}

- (NSString *)stringForNwPathStatus:(nw_path_status_t)status {
	switch(status) {
		case nw_path_status_satisfied:{
			return @"nw_path_status_satisfied";
		}
		case nw_path_status_invalid:{
			return @"nw_path_status_invalid";
		}
		case nw_path_status_satisfiable:{
			return @"nw_path_status_satisfiable";
		}
		case nw_path_status_unsatisfied:{
			return @"nw_path_status_unsatisfied";
		}
	}
}

- (void)stopMonitoring {
		//关闭通知.
	mStatus = StatusStopped;
	[[NSNotificationCenter defaultCenter] removeObserver:self];
	[mExecutor stopMonitoring];
	nw_path_monitor_cancel(mPathMonitor_cellular);
	mPathMonitor_cellular = nil;
}

	//通过判断网卡是否开启
+ (bool)isCelluarAvailableA {
	return NO;
}

	//通过判断celluar接口是否可用.
+ (bool)isCelluarAvailableB {
	return NO;
}

/**
 AfNetworking在wifi|cellular全部打开时,关闭wifi,会先进入notreachable,然后再进入cellular.这里我们判断notreachable时,如果流量是打开的,就为cellular.
 */
- (void)updateStatus {
		//根据status判断当前状态.
	JsNetworkReachablitiyStatus newStatus;
	switch(mAfStatus){
		case JsAfNetworkReachabilityStatusReachableViaWiFi:{
			if(mNwStatus_cellular == nw_path_status_satisfied) {
				newStatus = JsNetworkReachablitiyStatusReachableViaWiFiAndCellular;
			}
			else {
				newStatus = JsNetworkReachablitiyStatusReachableViaWiFi;
			}
			break;
		}
		case JsAfNetworkReachabilityStatusReachableViaWWAN:{
			newStatus = JsNetworkReachablitiyStatusReachableViaWCellular;
			break;
		}
		case JsAfNetworkReachabilityStatusUnknown:
		case JsAfNetworkReachabilityStatusNotReachable:{
			if(mNwStatus_cellular == nw_path_status_satisfied) {
				newStatus = JsNetworkReachablitiyStatusReachableViaWCellular;
			}
			else {
				newStatus = JsNetworkReachablitiyStatusNotReachable;
			}
			break;
		}
	}
	if(self.reachabilityStatus != newStatus) {
		self.reachabilityStatus = newStatus;
		dispatch_async(dispatch_get_main_queue(), ^{
			jslogv_fc(TAG, @"network change", @"current status is %d:%@,send notification",self.reachabilityStatus,[self statusString]);
			//通知的调用是直接在当前runloop执行.
			NSNotification * noti = [NSNotification notificationWithName:JsNetworkReachabilityChangeNotification object:self userInfo:nil];
			[[NSNotificationCenter defaultCenter]postNotification:noti];
			
		});
	}
}

#pragma mark 4 Event
-(void)onNetworkReachabilityChange:(NSNotification *)notification {
//	jslogd_fc(TAG, @"", @"Network reachablitiy change.");
//	[[JsLogManager sharedInstance] printLogFileDir];
	mAfStatus = [notification.userInfo[JsAfNetworkingReachabilityNotificationStatusItem] intValue];
	[self updateStatus];
}

+ (int)checkCellularPermision{
	CTCellularData *cellularData = [[CTCellularData alloc] init];
	cellularData.cellularDataRestrictionDidUpdateNotifier = ^(CTCellularDataRestrictedState state) {
		NSLog(@"cellular restricted state:%lu",(unsigned long)state);
	};
	return 0;
};

+(NSString *)nameForNwPathStatus:(nw_path_status_t)status {
	switch(status) {
				case nw_path_status_invalid:{
					return @"nw_path_status_invalid";
				}
		case nw_path_status_satisfied:{
			return @"nw_path_status_satisfied";
		}
		case nw_path_status_satisfiable:{
			return @"nw_path_status_satisfiable";
		}
		case nw_path_status_unsatisfied:{
			return @"nw_path_status_unsatisfied";
		}
	}
}


//如果流量权限没有打开,连接时unstatisfied.
+ (void)checkCurrentNetworkWithDomain_cellular:(void(^)(nw_path_status_t status))handler {
	nw_path_monitor_t monitor = nw_path_monitor_create_with_type(nw_interface_type_cellular);
	nw_path_monitor_set_update_handler(monitor, ^(nw_path_t  _Nonnull path) {
		nw_path_status_t status = nw_path_get_status(path);
		nw_path_monitor_cancel(monitor);
		if(handler) {
			handler(status);
		}
	});
	nw_path_monitor_set_queue(monitor, dispatch_get_global_queue(0, 0));
	nw_path_monitor_start(monitor);
}


//
+ (void)checkCurrentNetworkWithDomain_wifi:(NSString *)domain {
	nw_path_monitor_t monitor = nw_path_monitor_create_with_type(nw_interface_type_wifi);
	nw_path_monitor_set_update_handler(monitor, ^(nw_path_t  _Nonnull path) {
		nw_path_status_t status = nw_path_get_status(path);
		NSString * name = [self nameForNwPathStatus:status];
		NSLog(@"wifi status: %@",name);
		nw_path_monitor_cancel(monitor);
	});
	nw_path_monitor_set_queue(monitor, dispatch_get_global_queue(0, 0));
	nw_path_monitor_start(monitor);
}

/**
 逻辑:
 1,如果不能连接,直接返回不可达.
 2,如果可以通过是Reachable,再次通过两个具体的状态判断是哪个可以连接.
 //此方法会触发首次网络权限申请,适用于app请求之前调用.
 */
+ (void)checkCurerntNetworkWithDomain:(NSString *)domain handler:(void(^)(JsNetworkReachablitiyStatus status))handler {
	SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(nil,domain.UTF8String);
	SCNetworkReachabilityFlags flags;
//	[self checkCurrentNetworkWithDomain_wifi:nil];
//	[self checkCurrentNetworkWithDomain_cellular:nil];
	//此方法会触发首次网络权限申请,适用于app请求之前调用.
	SCNetworkReachabilityGetFlags(reachability, &flags);
//	if(flags&kSCNetworkReachabilityFlagsTransientConnection){
//		//表示临时性的.
//		NSLog(@"kSCNetworkReachabilityFlagsTransientConnection");
//	}
//	if(flags&kSCNetworkReachabilityFlagsReachable){
//		//可达的
//		NSLog(@"kSCNetworkReachabilityFlagsReachable");
//	}
//	if(flags&kSCNetworkReachabilityFlagsConnectionRequired){
//		NSLog(@"kSCNetworkReachabilityFlagsConnectionRequired");
//	}
//	if(flags&kSCNetworkReachabilityFlagsConnectionOnTraffic){
//		NSLog(@"kSCNetworkReachabilityFlagsConnectionOnTraffic");
//	}
//	if(flags&kSCNetworkReachabilityFlagsInterventionRequired){
//		NSLog(@"kSCNetworkReachabilityFlagsInterventionRequired");
//	}
//	if(flags&kSCNetworkReachabilityFlagsConnectionOnDemand){
//		NSLog(@"kSCNetworkReachabilityFlagsConnectionOnDemand");
//	}
//	if(flags&kSCNetworkReachabilityFlagsIsLocalAddress){
//		//连接localhost,访问本机.
//		NSLog(@"kSCNetworkReachabilityFlagsIsLocalAddress");
//	}
//	if(flags&kSCNetworkReachabilityFlagsIsDirect){
//		NSLog(@"kSCNetworkReachabilityFlagsIsDirect");
//	}
//	if(flags&kSCNetworkReachabilityFlagsIsWWAN){
//		//This flag indicates that the specified nodename or address can be reached via an EDGE, GPRS, or other "cell" connection.
//		NSLog(@"kSCNetworkReachabilityFlagsIsWWAN");
//	}
	__block JsNetworkReachablitiyStatus reachabilityStatus = JsNetworkReachablitiyStatusUnknown;
	//不可达
	if(!(flags&kSCNetworkReachabilityFlagsReachable)) {
		reachabilityStatus = JsNetworkReachablitiyStatusNotReachable;
		if(handler) {
			handler(reachabilityStatus);
		}
	}
	//如果是可以使用流量reach,说明wifi不可达.
	if(flags&kSCNetworkReachabilityFlagsIsWWAN) {
		reachabilityStatus = JsNetworkReachablitiyStatusReachableViaWCellular;
		if(handler) {
			handler(reachabilityStatus);
		}
	}
	else {
		//通过wifi抵达.
		[self checkCurrentNetworkWithDomain_cellular:^(nw_path_status_t status) {
			if(reachabilityStatus == nw_path_status_satisfied) {
				//流量也可用
				reachabilityStatus = JsNetworkReachablitiyStatusReachableViaWiFi;
			}
			else {
				//流量不可用
				reachabilityStatus = JsNetworkReachablitiyStatusReachableViaWiFiAndCellular;
			}
			if(handler) {
				handler(reachabilityStatus);
			}
		}];
	}

}

+ (NSString *)nameForStatus:(JsNetworkReachablitiyStatus)status {
	switch(status) {
		case JsNetworkReachablitiyStatusUnknown:{
			return @"JsNetworkReachablitiyStatusUnknown";
		}
		case JsNetworkReachablitiyStatusNotReachable:{
			return @"JsNetworkReachablitiyStatusNotReachable";
		}
		case JsNetworkReachablitiyStatusReachableViaWiFi:{
			return @"JsNetworkReachablitiyStatusReachableViaWiFi";
		}
		case JsNetworkReachablitiyStatusReachableViaWCellular:{
			return @"JsNetworkReachablitiyStatusReachableViaWCellular";
		}
		case JsNetworkReachablitiyStatusReachableViaWiFiAndCellular:{
			return @"JsNetworkReachablitiyStatusReachableViaWiFiAndCellular";
		}
	}
}

@end
